/**
 * @author YangDong
 */
import React, {Component} from 'react'
import {View, Text, StyleSheet, FlatList, ActivityIndicator, TouchableOpacity, ViewPropTypes,RefreshControl,Animated} from 'react-native'
import PropTypes from 'prop-types';
import {get, post, cancel} from "../fetch/Request";
import RNText from "../text/RNText";

const RefreshState = {
    Idle: 0, //闲置中
    HeaderRefreshing: 1, //头部刷新
    FooterRefreshing: 2, //尾部加载更多
    NoMoreData: 3, //没有更多数据
    Failure: 4, //失败
    EmptyData: 5, //空数据
    OverTime: 6,//超时
}

const RefreshType = {
    headerRefresh: 1, //上拉刷新
    footerRefresh: 2 //下拉加载更多
};
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
export default class RefreshFlatList extends Component {

    static propTypes = {
        url: PropTypes.string, //请求地址
        params: PropTypes.object,//请求参数
        method: PropTypes.oneOf(['post','get']),//请求方式
        timeout: PropTypes.number, //超时时间
        isRefresh: PropTypes.bool,//是否启用下拉
        isEndReached: PropTypes.bool, //是否启用上拉
        cursorIdField: PropTypes.string, //唯一标示字段名称
        pagingType: PropTypes.oneOf(['page','course']),
        color: PropTypes.string,//下拉控件颜色，仅用于android
        pageSizeField: PropTypes.string,//分页大小字段名称
        pageIndexFiled: PropTypes.string, //页数字段名称
        pageSize: PropTypes.number,//每页行数，默认15
        renderItem: PropTypes.func,//每行组件
        formatData: PropTypes.func,//整理数据，返回整理后的数据
        listRef: PropTypes.func,//list的ref
        footerContainerStyle: PropTypes.object,//footer组件的样式
        footerTextStyle: PropTypes.object,//底部组件text的样式
        footerRefreshingText: PropTypes.string,//加载更多的文字
        footerFailureText: PropTypes.string,//加载失败的文字
        footerNoMoreDataText: PropTypes.string,//没有更多数据的文字
        footerEmptyDataText: PropTypes.string,//空数据的文字
        footerOverTimeText: PropTypes.string,//超时文字
    }

    static defaultProps = {
        color: "red",
        pagingType: "page",
        isRefresh: true,
        isEndReached: true,
        cursorIdField: "cursorId",
        pageIndexFiled: "pageIndex",
        pageSizeField: "pageSize",
        method: 'post',
        timeout: 5,
        pageSize: 15,
        footerRefreshingText: '加载中...',
        footerFailureText: '失败了哦，点击重新加载',
        footerNoMoreDataText: '再怎么找也没有了',
        footerEmptyDataText: '好像什么东西都没有',
        footerOverTimeText: '加载超时了哦，点击重新加载',
        formatData: (data)=> {
            return {
                edges: data.obj,
                cursorId: data.cursorId,
                other: data.other
            };
        }
    }

    constructor(props){
        super(props);
        this.state = {
            refreshState: RefreshState.Idle,
            other: null,
            cursorId: "",
            headerSize: 0,
            footerSize: 0,
            data: []
        }
    }

    render() {
        let {renderItem, ...rest} = this.props;
        let onRefresh={};
        if(this.props.isRefresh){
            onRefresh = {
                onRefresh: ()=> this.onHeaderRefresh()
            };
        }
        let onEndReached={};
        if(this.props.isEndReached){
            onEndReached = {
                onEndReached: ()=> this.onEndReached()
            };
        }

        let ListHeaderComponent = {};
        if(this.props.renderListHeaderComponent && this.state.other){
            ListHeaderComponent = {
                ListHeaderComponent: ()=> this.props.renderListHeaderComponent(this.state.other)
            }
        }
        return (
            <AnimatedFlatList
                ref={(ref)=> this.props.listRef && this.props.listRef(ref)}
                data={this.state.data}
                refreshControl={
                    <RefreshControl {...onRefresh}
                                    colors={[this.props.color]}
                                    refreshing={ this.props.isRefresh?this.state.refreshState === RefreshState.HeaderRefreshing:false}/>
                }
                {...onEndReached}
                {...ListHeaderComponent}
                ListFooterComponent={()=> this.renderFooter()}
                onEndReachedThreshold={this.props.isEndReached?0.1:0}

                initialNumToRender={this.props.pageSize}
                renderItem={(info)=> renderItem(info)}

                {...rest}
            />
        )
    }

    //下拉刷新
    onHeaderRefresh(){
        if(this.state.refreshState === RefreshState.HeaderRefreshing
            || this.state.refreshState === RefreshState.FooterRefreshing) {return;}
        this.setState({
            refreshState: RefreshState.HeaderRefreshing
        },()=> this.sendRequest(RefreshType.headerRefresh));
    }

    //上拉加载更多
    onEndReached(){
        if(this.state.refreshState === RefreshState.HeaderRefreshing
            || this.state.refreshState === RefreshState.FooterRefreshing
            || this.state.refreshState === RefreshState.NoMoreData) return;
        this.setState({
            refreshState: RefreshState.FooterRefreshing
        },()=> this.sendRequest(RefreshType.footerRefresh));
    }

    //失败
    onFailure(){
        if(this.state.refreshState !== RefreshState.Failure) return;
        this.setState({
            refreshState: RefreshState.FooterRefreshing
        },()=> this.sendRequest(RefreshType.footerRefresh));
    }

    //空数据
    onEmptyData(){
        if(this.state.refreshState !== RefreshState.EmptyData) return;
        this.setState({
            refreshState: RefreshState.FooterRefreshing
        },()=> this.sendRequest(RefreshType.footerRefresh));
    }

    onOverTime(){
        if(this.state.refreshState !== RefreshState.OverTime) return;
        this.setState({
            refreshState: RefreshState.FooterRefreshing
        },()=> this.sendRequest(RefreshType.footerRefresh));
    }

    renderFooter = () => {
        let footer = null

        let footerContainerStyle = [styles.footerContainer, this.props.footerContainerStyle];
        let footerTextStyle = [styles.footerText, this.props.footerTextStyle];
        let {footerRefreshingText, footerFailureText, footerNoMoreDataText, footerEmptyDataText, footerOverTimeText} = this.props;

        switch (this.state.refreshState) {
            // case RefreshState.Idle:
            //     footer = (<View style={footerContainerStyle} />)
            //     break
            case RefreshState.Failure: {
                footer = (
                    <TouchableOpacity
                        style={footerContainerStyle}
                        onPress={() => {this.onFailure()}}
                    >
                        <RNText  style={footerTextStyle}>{footerFailureText}</RNText>
                    </TouchableOpacity>
                )
                break
            }
            case RefreshState.EmptyData: {
                footer = (
                    <TouchableOpacity
                        style={footerContainerStyle}
                        onPress={() => {this.onEmptyData()}}
                    >
                        <RNText  style={footerTextStyle}>{footerEmptyDataText}</RNText>
                    </TouchableOpacity>
                )
                break
            }
            case RefreshState.FooterRefreshing: {
                footer = (
                    <View style={footerContainerStyle} >
                        <ActivityIndicator size="small" color={this.props.color} />
                        <RNText  style={[footerTextStyle, {marginLeft: 7}]}>{footerRefreshingText}</RNText>
                    </View>
                )
                break
            }
            case RefreshState.NoMoreData: {
                footer = (
                    <View style={footerContainerStyle} >
                        <RNText  style={footerTextStyle}>{footerNoMoreDataText}</RNText>
                    </View>
                )
                break
            }
            case RefreshState.OverTime: {
                footer = (
                    <TouchableOpacity
                        style={footerContainerStyle}
                        onPress={() => {this.onOverTime()}}
                    >
                        <RNText  style={footerTextStyle}>{footerOverTimeText}</RNText>
                    </TouchableOpacity>
                )
                break
            }
        }
        return footer
    }

    componentDidMount(){
        //第一次加载，列表为下拉刷新状态，但请求应该是上拉加载更多
        if(this.props.isRefresh){
            this.setState({
                refreshState: RefreshState.HeaderRefreshing
            },()=> {
                this.sendRequest(RefreshType.footerRefresh);
            });
        }

        if(!this.props.isRefresh && this.props.isEndReached){
            this.setState({
                refreshState: RefreshState.FooterRefreshing
            },()=> {
                this.sendRequest(RefreshType.footerRefresh);
            });
        }
    }

    componentWillMount(){
        this.timer && clearTimeout(this.timer);
        cancel(this);
    }

    //发送请求
    sendRequest= (type)=>{
        //设置超时后断开
        this.timer = setTimeout(()=>{
            if(this.state.refreshState === RefreshState.HeaderRefreshing || RefreshState.FooterRefreshing){
                this.setState({
                    refreshState: RefreshState.OverTime
                },()=>{
                    cancel(this);
                });
            }
        },this.props.timeout * 1000);

        let params = this.props.params;

        if(this.props.pagingType === "page"){
            params[this.props.pageIndexFiled] = type === RefreshType.headerRefresh?
                1
                :
                Math.ceil(this.state.data.length/this.props.pageSize)+1;//上拉加载更多时的页数
            params[this.props.pageSizeField] = this.props.pageSize;
        }else{
            params[this.props.pageIndexFiled] = type === RefreshType.headerRefresh?
                this.state.headerSize
                :
                Math.ceil(this.state.footerSize/this.props.pageSize)+1;//上拉加载更多时的页数
            params[this.props.pageSizeField] = this.props.pageSize;
            params[this.props.cursorIdField] = this.state.cursorId;
            params["cursor"] =  type;
        }
        let promise = this.props.method === 'post'?post(
            this,
            this.props.url,
            params
        ): get(
            this,
            this.props.url,
            params
        );
        promise.then((response) => {
            if(response.ok){
                return response.json();
            }else{
                this.setState({
                    refreshState: RefreshState.Failure
                });
                return;
            }
        }).then((json) => {
            let data = this.props.formatData(json).edges;//{edges:[],cursorId:"111111111"}
            let cursorId = this.props.formatData(json).cursorId;
            let other = this.props.formatData(json).other || {};
            let state = RefreshState.Idle;
            let dataSource = this.state.data;
            let headerSize = this.state.headerSize;
            let footerSize = this.state.footerSize;

            if(type === RefreshType.headerRefresh){
                if(this.props.pagingType === "page"){
                    dataSource = data;
                }else{
                    data.forEach((val,index)=> {
                        dataSource.unshift(val);
                    })
                    headerSize = headerSize + data.length;
                }
                if(data.length === 0){
                    state = RefreshState.EmptyData;
                }else {
                    state = RefreshState.Idle;
                }
            }else if(type === RefreshType.footerRefresh){
                dataSource = dataSource.concat(data);
                if(this.props.pagingType === "course"){
                    footerSize = footerSize + data.length;
                }
                if(data.length < this.props.pageSize){
                    state = RefreshState.NoMoreData;
                }else {
                    state = RefreshState.Idle;
                }
            }
            this.setState({
                data: dataSource,
                other: other,
                footerSize: footerSize,
                headerSize: headerSize,
                refreshState: state,
                cursorId: cursorId
            });
        }).catch((err) => {
            this.setState({
                refreshState: RefreshState.Failure
            })
        }).done(()=>{
            this.timer && clearTimeout(this.timer);
        });
    }

    updateDataSource(data){
        this.setState({
            data: data
        });
    }

    updateDataByIndex(data,index){
        let dataSource = this.state.data;
        dataSource[index] = data;
        this.setState({
            data: dataSource
        });
    }

    unshiftHeaderData(array){
        let dataSource = this.state.data;
        dataSource.unshift(...array);
        this.setState({
            data: dataSource,
            headerSize: this.state.headerSize+array.size
        });
    }

    pushFooterData(array){
        let dataSource = this.state.data;
        dataSource.concat(array);
        this.setState({
            data: dataSource,
            footerSize: this.state.footerSize+array.size
        });
    }
}

const styles = StyleSheet.create({
    footerContainer: {
        flex: 1,
        flexDirection: 'row',
        justifyContent: 'center',
        alignItems: 'center',
        padding: 10,
        height: 44,
    },
    footerText: {
        fontSize: 11,
        color: '#555555'
    }
})
